package com.hk.core.redis.locks;

import com.hk.commons.util.Lazy;
import com.hk.commons.util.SpringContextHolder;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * 使用 Spring {@link  ThreadPoolTaskScheduler} 定时续期
 *
 * @author Kevin
 * @date 2022-11-20 22:08
 */
class ThreadPoolTaskScheduleRenewalStrategy implements RedisLockRenewalStrategy {

    private static final ConcurrentHashMap<String, ScheduledFuture<?>> FUTURE_MAP;

    private static final Lazy<ThreadPoolTaskScheduler> POOL_EXECUTOR =
            Lazy.of(() -> SpringContextHolder.getBeanIfExist(ThreadPoolTaskScheduler.class)
                    .orElseGet(() -> {
                        var executor = new ThreadPoolTaskScheduler();
                        executor.setThreadNamePrefix("TPT-Redis-Lock-");
                        executor.setPoolSize(Runtime.getRuntime().availableProcessors());
                        executor.initialize();
                        executor.setRemoveOnCancelPolicy(true);
                        return executor;
                    }));

    static {
        FUTURE_MAP = new ConcurrentHashMap<>(128);
    }

    @Override
    public void renewal(String key, Runnable task, long initialDelay, long period, TimeUnit unit) {
        var fixedRate = POOL_EXECUTOR.get().getScheduledExecutor()
                .scheduleWithFixedDelay(task, initialDelay, period, unit);
        var oldFuture = FUTURE_MAP.put(key, fixedRate);
        if (Objects.nonNull(oldFuture)) {
            oldFuture.cancel(true);
        }
    }

    @Override
    public void cancel(String key) {
        var future = FUTURE_MAP.remove(key);
        if (Objects.nonNull(future)) {
            future.cancel(true);
        }
    }

    @Override
    public void shutdown() {
        try {
            POOL_EXECUTOR.get().shutdown();
        } catch (Exception e) {
            // ignore.
        }
    }
}
